﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;

namespace HigLabo.WindowsAzure.RestService.Extensions
{
    internal static class XmlParserExtensions
    {
        /// <summary>
        /// 指定した名称をローカル名に持つ最初の要素を取得します
        /// （XML名前空間によらずに要素を取得する際に使用します。）
        /// </summary>
        /// <param name="element"></param>
        /// <param name="elementName"></param>
        /// <returns></returns>
        public static XElement ElementByLocalName(this XElement element, string elementName)
        {
            if (element == null)
            {
                return null;
            }
            return element.Elements().FirstOrDefault(item => item.Name.LocalName == elementName);
        }
        /// <summary>
        /// 指定した名称をローカル名に持つ要素を取得します
        /// （XML名前空間によらずに要素を取得する際に使用します。）
        /// </summary>
        /// <param name="element"></param>
        /// <param name="elementName"></param>
        /// <returns></returns>
        public static IEnumerable<XElement> ElementsByLocalName(this XElement element, string elementName)
        {
            if (element == null)
            {
                return null;
            }
            return element.Elements().Where(item => item.Name.LocalName == elementName);
        }
        /// <summary>
        /// 指定した名称をローカル名に持つ最初の要素を取得します
        /// （XML名前空間に従って要素を取得する際に使用します。）
        /// </summary>
        /// <param name="element"></param>
        /// <param name="elementName"></param>
        /// <returns></returns>
        public static XElement ElementUseNamespace(this XElement element, string elementName)
        {
            if (element == null)
            {
                return null;
            }
            var name = element.Name.Namespace.GetName(elementName);
            return element.Element(name);
        }
        /// <summary>
        /// 指定した名称をローカル名に持つ要素を取得します
        /// （XML名前空間に従って要素を取得する際に使用します。）
        /// </summary>
        /// <param name="element"></param>
        /// <param name="elementName"></param>
        /// <returns></returns>
        public static IEnumerable<XElement> ElementsUseNamespace(this XElement element, string elementName)
        {
            if (element == null)
            {
                return null;
            }
            var name = element.Name.Namespace.GetName(elementName);
            return element.Elements(name);
        }
        /// <summary>
        /// 要素の値を取得します。
        /// 要素がnullもしくは、要素値がnullの場合、空文字を返します。
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static String ValueOrEmpty(this XElement element)
        {
            if (element == null)
            {
                return "";
            }
            if (String.IsNullOrEmpty(element.Value))
            {
                return "";
            }
            return element.Value;
        }
        /// <summary>
        /// Get Element Value as Boolean
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static Boolean? ValueToBoolean(this XElement element)
        {
            return element.ValueOrEmpty().ToBoolean();
        }
        /// <summary>
        /// Get Element Value as Boolean
        /// </summary>
        /// <param name="element"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static Boolean ValueToBoolean(this XElement element,Boolean defaultValue)
        {
            return element.ValueOrEmpty().ToBoolean(defaultValue);
        }
        /// <summary>
        /// Get Element Value as Int32
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static Int32? ValueToInt32(this XElement element)
        {
            return element.ValueOrEmpty().ToInt32();
        }
        /// <summary>
        /// Get Element Value as Int32
        /// </summary>
        /// <param name="element"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static Int32 ValueToInt32(this XElement element, Int32 defaultValue)
        {
            return element.ValueOrEmpty().ToInt32(defaultValue);
        }
        /// <summary>
        /// Get Element Value as Enum
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="element"></param>
        /// <returns></returns>
        public static T? ValueToEnum<T>(this XElement element) where T : struct
        {
            return element.ValueOrEmpty().ToEnum<T>();
        }
        /// <summary>
        /// Get Element Value as Enum
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="element"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T ValueToEnum<T>(this XElement element, T defaultValue) where T : struct
        {
            return element.ValueOrEmpty().ToEnum(defaultValue);
        }
        /// <summary>
        /// Get child element value
        /// </summary>
        /// <remarks>find element by local name.</remarks>
        /// <param name="element"></param>
        /// <param name="childElementName"></param>
        /// <returns></returns>
        public static String ValueOrEmpty(this XElement element, String childElementName)
        {
            return element.ElementByLocalName(childElementName).ValueOrEmpty();
        }
        /// <summary>
        /// Get child element value as Boolean
        /// </summary>
        /// <remarks>find element by local name.</remarks>
        /// <param name="element"></param>
        /// <param name="childElementName"></param>
        /// <returns></returns>
        public static Boolean? ValueToBoolean(this XElement element, String childElementName)
        {
            return element.ValueOrEmpty(childElementName).ToBoolean();
        }
        /// <summary>
        /// Get child element value as Boolean
        /// </summary>
        /// <remarks>find element by local name.</remarks>
        /// <param name="element"></param>
        /// <param name="childElementName"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static Boolean ValueToBoolean(this XElement element, String childElementName, Boolean defaultValue)
        {
            return element.ValueOrEmpty(childElementName).ToBoolean(defaultValue);
        }
        /// <summary>
        /// Get child element value as Int32
        /// </summary>
        /// <remarks>find element by local name.</remarks>
        /// <param name="element"></param>
        /// <param name="childElementName"></param>
        /// <returns></returns>
        public static Int32? ValueToInt32(this XElement element, String childElementName)
        {
            return element.ValueOrEmpty(childElementName).ToInt32();
        }
        /// <summary>
        /// Get child element value as Int32
        /// </summary>
        /// <remarks>find element by local name.</remarks>
        /// <param name="element"></param>
        /// <param name="childElementName"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static Int32 ValueToInt32(this XElement element, String childElementName, Int32 defaultValue)
        {
            return element.ValueOrEmpty(childElementName).ToInt32(defaultValue);
        }
        /// <summary>
        /// Get child element value as Enum
        /// </summary>
        /// <remarks>find element by local name.</remarks>
        /// <typeparam name="T"></typeparam>
        /// <param name="element"></param>
        /// <param name="childElementName"></param>
        /// <returns></returns>
        public static T? ValueToEnum<T>(this XElement element, String childElementName) where T : struct
        {
            return element.ValueOrEmpty(childElementName).ToEnum<T>();
        }
        /// <summary>
        /// Get child element value as Enum
        /// </summary>
        /// <remarks>find element by local name.</remarks>
        /// <typeparam name="T"></typeparam>
        /// <param name="element"></param>
        /// <param name="childElementName"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T ValueToEnum<T>(this XElement element, String childElementName, T defaultValue) where T : struct
        {
            return element.ValueOrEmpty(childElementName).ToEnum(defaultValue);
        }



        /// <summary>
        /// 属性値を取得します
        /// </summary>
        /// <param name="element"></param>
        /// <param name="attributeName"></param>
        /// <returns></returns>
        public static String AttributeValue(this XElement element, string attributeName)
        {
            if (element == null)
            {
                return null;
            }
            var att = element.Attribute(XName.Get(attributeName));
            if (att == null)
            {
                return null;
            }
            return att.Value;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="element"></param>
        /// <param name="attributeName"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static String AttributeValue(this XElement element, string attributeName, String defaultValue)
        {
            var v = AttributeValue(element, attributeName);
            if (String.IsNullOrEmpty(v))
            {
                return defaultValue;
            }
            return (String)v;
        }
        /// <summary>
        /// XMLを指定したパスから読み込みます
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static XDocument GetLoadXMLFile(this string path)
        {
            if (File.Exists(path) == false)
            {
                return null;
            }
            return XDocument.Load(path);
        }
        /// <summary>
        /// 属性を設定します
        /// </summary>
        /// <param name="element"></param>
        /// <param name="attributeName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static XAttribute SetAttribute(this XElement element, string attributeName, object value)
        {
            if (element == null)
            {
                return null;
            }
            var att = element.Attribute(attributeName);
            if (att != null)
            {
                att.Value = value == null ? "" : value.ToString();
            }
            else
            {
                att = new XAttribute(attributeName, value == null ? "" : value.ToString());
                element.Add(att);
            }
            return att;
        }

        
    }
}
